/* 
 * 
 * Author: Jakub Krajniak (c) 2006-2007
 * Contact: jkrajniak@gmail.com
 * Licence: GPL
 *
 * 
 * This program try to build Mealy automate from filtron's description
 * It's support only manual creating. Automating process probably would
 * be support in future version. 
 * 
 * Some comments for source are in polish. Very sorry for that unconvince. 
 * If you have question, send mail to me.
 * 
*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Filtron
{
    public class Automat
    {
        public Automat(string[] plik,int mx)
        {
        }
        public Automat(int mx)
        {
            maxStates = mx;
        }
        public Automat(List<string[]> next_state, List<string[]> output)
        {
            int counter = 0;
            foreach(string[] st in next_state)
            {
                Dictionary<int, int> ns = new Dictionary<int, int>();
                for (int i = 0; i < st.Length; i++)
                {
                    if (st[i] == "-")
                        ns.Add(i, -1);
                    else
                        ns.Add(i, alp.decode(st[i]));
                }
                stan_nastepny.Add(counter, ns);
                counter++;
            }
            counter = 0;
            foreach (string[] st in output)
            {
                Dictionary<int, int> ns = new Dictionary<int, int>();
                for (int i = 0; i < st.Length; i++)
                {
                    if (st[i] == "-")
                        ns.Add(i, -1);
                    else
                        ns.Add(i, alp.decode(st[i]));
                }
                odpowiedzi.Add(counter, ns);
                counter++;
            }
        }
        public Automat(Dictionary<int,Dictionary<int,int> > states, Dictionary<int,Dictionary<int,int> > output)
        {
            stan_nastepny = states;
            odpowiedzi = output;
            maxStates = stan_nastepny[0].Values.Count-1;
        }
        /// <summary>
        /// return automate answer for spec state and input string (before conversion)
        /// if non, return "-1"
        /// </summary>
        /// <param name="state"></param>
        /// <param name="enter"></param>
        /// <returns></returns>
        public string get_answer(int state, string enter)
        {
            return alp.code(odpowiedzi[state][alp.decode(enter)]);
        }
        /// <summary>
        /// set for current state and enter symbol: next state, answer
        /// </summary>
        /// <param name="state">current automate state</param>
        /// <param name="enter">input symbol</param>
        /// <param name="odpowiedz">output symbol</param>
        /// <param name="next_state">next automate state</param>
        public void set(int state, int enter, int odpowiedz, int next_state)
        {
            if (odpowiedzi.ContainsKey(state))
            {
                if (odpowiedzi[state].ContainsKey(enter))
                    if (odpowiedzi[state][enter] == -1)
                        odpowiedzi[state][enter] = odpowiedz;
                    else
                        odpowiedzi[state][enter] =  odpowiedz;
            }
            else
            {
                Dictionary<int, int> dd = new Dictionary<int, int>();
                for (int i = 0; i <= maxStates; i++)
                {
                    dd.Add(i, -1);
                }
                dd[enter] = odpowiedz;
                odpowiedzi.Add(state, dd);
            }
            if (stan_nastepny.ContainsKey(state))
            {
                if (stan_nastepny[state].ContainsKey(enter))
                    if (stan_nastepny[state][enter] == -1)
                        stan_nastepny[state][enter] = next_state;
                    else
                        stan_nastepny[state][enter] = next_state;
            }
            else
            {
                Dictionary<int, int> dd = new Dictionary<int, int>();
                for (int i = 0; i <= maxStates; i++)
                {
                    dd.Add(i, -1);
                }
                dd[enter] = next_state;
                stan_nastepny.Add(state, dd);
            }

        }
        /// <summary>
        /// returning automate response table
        /// </summary>
        /// <returns></returns>
        public List<List<int> > get_output_table()
        {
            List<List<int> > ret = new List<List<int>>();
            foreach (KeyValuePair<int, Dictionary<int, int> > key in odpowiedzi)
            {
                List<int> an = new List<int>();
                foreach (KeyValuePair<int, int> kkey in key.Value)
                {
                    an.Add(kkey.Value);
                }
                ret.Add(an);
            }
            return ret;
        }
        /// <summary>
        /// returnint next state table
        /// </summary>
        /// <returns></returns>
        public List<List<int>> get_state_table()
        {
            List<List<int>> ret = new List<List<int>>();
            foreach (KeyValuePair<int, Dictionary<int, int>> key in stan_nastepny)
            {
                List<int> an = new List<int>();
                foreach (KeyValuePair<int, int> kkey in key.Value)
                {
                    an.Add(kkey.Value);
                }
                ret.Add(an);
            }
            return ret;
        }
        public int currentState
        {
            get { return myStan; }
        }
        private int myStan = 0;
        /// <summary>
        /// Key of first dictionary is a state, second dictionary's key is a input symbol. Returning is a output symbol
        /// </summary>
        public Dictionary<int, Dictionary<int,int> > odpowiedzi = new Dictionary<int, Dictionary<int,int> >();
        /// <summary>
        /// Key of first dictionary is a state, second dictionary key's is a input symbol. Returning is next state
        /// </summary>
        public Dictionary<int, Dictionary<int, int>> stan_nastepny = new Dictionary<int, Dictionary<int, int> >();
        public Alphabet alp = new Alphabet(64);
        public int MaxStates
        {
            get { return MaxStates; }
            set {
                for (int state = 0; state < odpowiedzi.Count; state++)
                {
                    Dictionary<int, int> ot = odpowiedzi[state];
                    for (int i = maxStates+1; i <= value; i++)
                    {
                        ot.Add(i, -1);
                    }
                    odpowiedzi[state] = ot;
                }
                maxStates = value;
            }
        }
        private int maxStates = 0;
    }
    public class Filtron
    {
        public Filtron(List<string[]> d)
        {
            bool segment = false;
            foreach (string s in d[0]) // counting filtron length
            {
                if (s != "0")
                {
                    mySegment++;
                }
            }
            bool aktywnosc = false;
            int last_pos = 0;
            int pos = 0;
            myD = new int[d.Count];
            int counter = 0;
            foreach (string[] line in d)
            {
                aktywnosc = false;
                foreach (string znak in line)
                {
                    if(znak != "0" && aktywnosc == false)
                    {
                        try
                        {
                            myLeftChars.Add(alp.decode(znak));
                        }
                        catch (MyErrors er)
                        {
                            throw er;
                        }
                        aktywnosc = true;
                        pos = Array.IndexOf(line, znak);
                        myD[counter] = pos - last_pos;
                        last_pos = pos;
                    }
                    if( maxInputSymbol < alp.decode(znak))
                    {
                        maxInputSymbol = alp.decode(znak);
                    }
                }
                counter++;
            }

        }
        /// <summary>
        /// Left first chars of filtron
        /// </summary>
        public List<int> LeftChars
        {
            get { return myLeftChars; }
        }
        /// <summary>
        /// for each filtron orbits returning latency
        /// </summary>
        public int[] D
        {
            get { return myD; }
        }
        /// <summary>
        /// return filtron Length
        /// </summary>
        public int Length
        {
            get { return mySegment; }
        }
        /// <summary>
        /// returning max input symbol
        /// </summary>
        public int MaxSymbol
        {
            get { return maxInputSymbol; }
        }
        public Alphabet ABC
        {
            get { return alp; }
        }
        private Alphabet alp = new Alphabet(64);
        private int[] myD;
        private List<int> myLeftChars = new List<int>();
        private int mySegment = 0;
        private int maxInputSymbol = 0;
    }
    public class Operation
    {
        public Operation()
        {
        }
        public Operation(int stateCount)
        {
            for (int i = 0; i <= stateCount; i++)
            {
                operationDict.Add(alp.All_symbols()[i], "");
            }
        }
        public void changeSettings(int stateCount)
        {
            if(stateCount > operationDict.Keys.Count-1)
                for(int i = operationDict.Keys.Count; i<=stateCount; i++)
                    operationDict.Add(alp.All_symbols()[i], "");
        }
        public void SetOutput(string input, string output)
        {
            if (operationDict.ContainsKey(input))
                operationDict[input] = output;
            else
                operationDict.Add(input, output);
        }
        public string GetOutput(string input)
        {
            if(operationDict.ContainsKey(input))
                return operationDict[input];
            else
                return "";
        }
        public string GetOperationLine()
        {
            string ret = "";
            foreach (KeyValuePair<string, string> k in operationDict)
            {
                if (k.Value.ToString() == "")
                    ret += "-";
                else
                    ret += k.Value.ToString();
            }
            return ret;
        }
        private Dictionary<string, string> operationDict = new Dictionary<string, string>();
        private Alphabet alp = new Alphabet();
    }
    public class OperationSet
    {
        public OperationSet()
        {
        }
        public OperationSet(int segmentSize, int stateCount, ref System.Windows.Forms.ToolStripStatusLabel hOpLabel, ref System.Windows.Forms.ToolStripStatusLabel fOpLabel)
        {
            init(segmentSize, stateCount);
            myhOpLabel = hOpLabel;
            myfOpLabel = fOpLabel;
            //myAutomateExtinction.Add(new Regex("^\w000"));
        }

        private void init(int segmentSize, int stateCount)
        {
            for (int i = 0; i <= stateCount; i++)
                hOperations.Add(alp.All_symbols()[i], new Operation(stateCount));
            for (int i = 0; i < segmentSize - 1; i++)
                fOperations.Add(new Operation(stateCount));
            mySegmentSize = segmentSize;
            myStateCount = stateCount;
            myAutomateExtinction = new List<Regex>();
        }

        public void changeSettings(int segmentSize, int stateCount)
        {
            if (stateCount > myStateCount)
            {
                for (int i = myStateCount + 1; i <= stateCount; i++)
                    hOperations.Add(alp.All_symbols()[i], new Operation(stateCount));
                foreach (KeyValuePair<string, Operation> k in hOperations)
                {
                    hOperations[k.Key].changeSettings(stateCount);
                }
                for (int i = 0; i < fOperations.Count; i++)
                {
                    fOperations[i].changeSettings(stateCount);
                } 
                myStateCount = stateCount;
            }
            if (segmentSize > mySegmentSize)
            {
                for (int i = mySegmentSize; i < segmentSize; i++)
                    fOperations.Add(new Operation(stateCount));
                mySegmentSize = segmentSize;
            }
            else
            {
                for (int i = segmentSize-1; i < mySegmentSize-1; i++)
                    fOperations.RemoveAt(i);
                mySegmentSize = segmentSize;
            }
        }

        public OperationSet(int segmentSize, int stateCount)
        {
            init(segmentSize, stateCount);
        }

        public void PutFOutput(string input, string output,int fFunction)
        {
            if (fFunction > mySegmentSize)
                throw new MyErrors("f function not found");
            else {
                if (fOperations[fFunction].GetOutput(input) != "" && fOperations[fFunction].GetOutput(input) != output)
                    throw new MyErrors("F"+fFunction.ToString()+" Incorect output. For input: "+input+" output is: "+output+" should be: "+fOperations[fFunction].GetOutput(input));
                fOperations[fFunction].SetOutput(input, output);
                if(myfOpLabel != null)
                    myfOpLabel.Text = (fFunction+1).ToString();
            }
        }

        public void ChangeFOutput(string input, string output, int fFunction)
        {
            if (fFunction > mySegmentSize)
                throw new MyErrors("f function not found");
            else
            {
                fOperations[fFunction].SetOutput(input, output);
            }
        }
        
        public void PutHOutput(string input, string output, string jSymbol)
        {
            if (!hOperations.ContainsKey(jSymbol))
                throw new MyErrors(jSymbol + " not found");
            else
            {
                if(hOperations[jSymbol].GetOutput(input) != "" && hOperations[jSymbol].GetOutput(input) != output)
                    throw new MyErrors("H"+jSymbol+" Incorect output. For input: "+input+" output is: "+output+" should be: "+hOperations[jSymbol].GetOutput(input));
                    //throw new Exception("H Incorect output. For input: "+input+" output is: "+output+" should be: "+hOperations[jSymbol].GetOutput(input));
                hOperations[jSymbol].SetOutput(input, output);
                if(myhOpLabel != null)
                    myhOpLabel.Text = jSymbol;
            }
        }

        public void ChangeHOutput(string input, string output, string jSymbol)
        {
            if (!hOperations.ContainsKey(jSymbol))
                throw new MyErrors(jSymbol + " not found");
            else
            {
                //throw new Exception("H Incorect output. For input: "+input+" output is: "+output+" should be: "+hOperations[jSymbol].GetOutput(input));
                hOperations[jSymbol].SetOutput(input, output);
                //myhOpLabel.Text = jSymbol;
            }
        }
        public void RemoveHOperation(string jSymbol)
        {
            if(!hOperations.ContainsKey(jSymbol))
                throw new MyErrors(jSymbol + " not found");
            else
            {
                hOperations.Remove(jSymbol);
            }
        }

        public void PutHLine(string line, string jSymbol)
        {
            for (int i = 0; i <= myStateCount; i++)
            {
                string inputChar = alp.All_symbols()[i];
                string outputChar = line[i].ToString();
                PutHOutput(inputChar, outputChar, jSymbol);
            }
        }
        public void PutFLine(string line, int fFunction)
        {
            for (int i = 0; i <= myStateCount; i++)
            {
                string inputChar = alp.All_symbols()[i];
                string outputChar = line[i].ToString();
                PutFOutput(inputChar, outputChar, fFunction);
            }
        }
        private List<Regex> myAutomateExtinction;
        private Dictionary<string, Operation> hOperations = new Dictionary<string, Operation>();
        private List<Operation> fOperations = new List<Operation>();
        private Alphabet alp = new Alphabet();
        private int mySegmentSize = 0;
        private int myStateCount = 0;
        public int SegmentSize
        {
            get { return mySegmentSize; }
           
        }
        public int StateCount
        {
            get { return myStateCount; }
        }
        public bool hasHOperation(string hOperation)
        {
            if(hOperations.ContainsKey(hOperation))
                return true;
            else
                return false;
        }
        public string GetFOutput(string input, int fOperation)
        {
            if (hasFOperation(fOperation))
                return fOperations[fOperation].GetOutput(input);
            else
                return "";
        }
        public string GetHOutput(string input, string jSymbol)
        {
            if (hasHOperation(jSymbol))
                return hOperations[jSymbol].GetOutput(input);
            else
                return "";
        }
        public bool hasFOperation(int fOperation)
        {
            if (fOperations.Count > fOperation)
                return true;
            else
                return false;
        }
        public Dictionary<string,string> GetHLines()
        {
            Dictionary<string, string> ret = new Dictionary<string, string>();
            foreach (KeyValuePair<string, Operation> k in hOperations)
            {
                ret.Add(k.Key, k.Value.GetOperationLine());   
            }
            return ret;
        }
        public List<string> GetFLines()
        {
            List<string> ret = new List<string>();
            for (int i = 0; i < fOperations.Count; i++)
            {
                ret.Add(fOperations[i].GetOperationLine());
            }
            return ret;
        }
        public bool AutomateTerminate(string st)
        {
            bool ret = false;
            foreach (Regex r in myAutomateExtinction)
            {
                if(r.IsMatch(st))
                    ret = true;
            }
            return ret;
        }
        private System.Windows.Forms.ToolStripStatusLabel myhOpLabel;
        private System.Windows.Forms.ToolStripStatusLabel myfOpLabel;
    }
}
